package com.foreveross.crawl.adapter.sub.impl20140402.v3.xiechen;

import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.adapter.sub.impl20140402.v3.XieChenAdapter;
import com.foreveross.crawl.common.util.RegHtmlUtil;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.TransitEntity;
import com.foreveross.crawl.domain.airfreight.doub.*;
import com.foreveross.taskservice.common.bean.TaskModel;
import com.google.common.collect.Maps;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.methods.HttpPost;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 携程国际往返程
 *
 * @author xiangsf 2014-07-18
 */
public class XieChenInterRoundTrip {
    protected Log logger = LogFactory.getLog(getClass());

    private final static String DATA_AJAX_REQUEST_URL = "http://flights.ctrip.com/international/AjaxRequest/UI2_0/SearchResultHandler.ashx";

    private TaskModel taskQueue;

    private XieChenAdapter adapter;

    private String conditions = null;
    private String refUrl = null;
    private List<DoublePlaneInfoEntity> roundTrips = null;

    public XieChenInterRoundTrip(XieChenAdapter adapter, TaskModel taskQueue) {
        this.adapter = adapter;
        this.taskQueue = taskQueue;
        roundTrips = new ArrayList<DoublePlaneInfoEntity>();
    }

    private void fetchEnterPage() throws Exception {
        StringBuffer url = new StringBuffer("http://flights.ctrip.com/international/round-");
        Map<String, String> params = new HashMap<String, String>();
        HttpPost post = null;
        String html = null;
        try {
            url.append(convertCityCode(taskQueue.getFromCity())).append("-").append(convertCityCode(taskQueue.getToCity())).append("-")
                    .append(convertCityCode(taskQueue.getFromCity())).append("-").append(convertCityCode(taskQueue.getToCity()));
            //url.append("sha-par-sha-par");
            params.put("txtEndCityCode2", "");
            params.put("txtEndCityCode1", "");
            params.put("txtEndAddress2", "");
            params.put("txtEndAddress1", "");
            params.put("txtDatePeriod2", "");
            params.put("txtDatePeriod1", "");
            params.put("txtBeginCityCode2", "");
            params.put("txtBeginCityCode1", "");
            params.put("txtBeginAddress2", "");
            params.put("txtBeginAddress1", "");
            params.put("txtAirline", "");
            params.put("Quantity", "1");
            params.put("HomeCityID", "2");
            params.put("homecity_name", taskQueue.getFromCityName() + "(" + taskQueue.getFromCity() + ")");
            params.put("FlightWay", "d");
            params.put("Eligibility", "");
            params.put("drpSubClass", "Y");
            params.put("destcityID", "250");
            params.put("destcity1_name", taskQueue.getToCityName() + "(" + taskQueue.getToCity() + ")");
            params.put("DDatePeriod1", taskQueue.getFlightDate());
            params.put("childtype", "ADT");
            params.put("Airline", "All");
            params.put("ADatePeriod1", taskQueue.getReturnGrabDate());
            post = adapter.getBasePost(url.toString(), params);
            post.setHeader("Referer", url.toString());
            post.setHeader("Host", "flights.ctrip.com");
            post.setHeader("Connection", "keep-alive");
            post.setHeader("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
            post.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            html = adapter.excuteRequest(adapter.getHttpClient(), post, "GBK");
            adapter.appendPageContents(html);
            conditions = RegHtmlUtil.regStr(html, "condition = '(\\{\"FlightWay\":.*\\})';.*if \\(window.simpleLoader\\)");
            refUrl = url.toString();
            logger.info("在第一个请求页得到的动态参数：" + conditions);
        } finally {
            url = null;
            params = null;
            post = null;
            html = null;
        }
    }

    private String fetchFirstSearch() throws Exception {
        HttpPost post = null;
        String html = null;
        Map<String, String> params = new HashMap<String, String>();
        try {
            params.put("SearchMode", "Search");
            params.put("condition", conditions);
            params.put("DisplayMode", "RoundTripGroup");
            post = adapter.getBasePost(DATA_AJAX_REQUEST_URL, params);
            post.setHeader("Referer", refUrl);
            post.setHeader("Host", "flights.ctrip.com");
            post.setHeader("Connection", "keep-alive");
            post.setHeader("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
            post.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            html = adapter.excuteRequest(post);
            adapter.appendPageContents(html);
            return html;
        } finally {
            post = null;
            html = null;
        }
    }

    private String fetchSecondSearch(JSONObject json) throws Exception {
        HttpPost post = null;
        String html = null;
        Map<String, String> params = new HashMap<String, String>();
        try {
            params.put("SearchMode", "TokenSearch");
            params.put("condition", conditions);
            params.put("DisplayMode", "RoundTripGroup");
            params.put("SearchIndex", "1");
            params.put("SearchToken", json.getJSONArray("PartitionToken").getString(0));
            params.put("t", String.valueOf(System.currentTimeMillis()));
            post = adapter.getBasePost(DATA_AJAX_REQUEST_URL, params);
            post.setHeader("Referer", refUrl);
            post.setHeader("Host", "flights.ctrip.com");
            post.setHeader("Connection", "keep-alive");
            post.setHeader("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
            post.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            html = adapter.excuteRequest(post);
            adapter.appendPageContents(html);
            return html;
        } finally {
            post = null;
            html = null;
        }
    }

    private String fetchThirdSearch(JSONObject json) throws Exception {
        HttpPost post = null;
        String html = null;
        Map<String, String> params = new HashMap<String, String>();
        try {
            params.put("SearchMode", "TokenSearch");
            params.put("condition", conditions);
            params.put("DisplayMode", "RoundTripGroup");
            params.put("SearchIndex", "2");
            params.put("SearchToken", json.getJSONArray("PartitionToken").getString(1));
            params.put("t", String.valueOf(System.currentTimeMillis()));
            post = adapter.getBasePost(DATA_AJAX_REQUEST_URL, params);
            post.setHeader("Referer", refUrl);
            post.setHeader("Host", "flights.ctrip.com");
            post.setHeader("Connection", "keep-alive");
            post.setHeader("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
            post.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            html = adapter.excuteRequest(post);
            adapter.appendPageContents(html);
            return html;
        } finally {
            post = null;
            html = null;
        }
    }

    private void parseJSONData(JSONObject json) throws Exception {
        DoublePlaneInfoEntity dpie = null;
        ReturnDoublePlaneInfoEntity rdpie = null;
        List<TransitEntity> goTransits = null;
        TransitEntity transitEntity = null;
        List<ReturnTransitEntity> backTransits = null;
        ReturnTransitEntity returnTransitEntity = null;
        CabinEntity goCabin = null;
        ReturnCabinEntity backCabin = null;
        JSONArray roundTripFlightList = json.getJSONArray("RoundTripFlightList");
        JSONObject fi = null;
        JSONObject gofi = null;
        JSONObject backfi = null;
        JSONObject tfi = null;
        JSONObject cabin = null;
        JSONArray flightInfo = null;
        JSONArray fareList = null;
        JSONArray flightDetail = null;
        logger.info("解析出的航班数量是：" + roundTripFlightList.size());
        for (int i = 0; i < roundTripFlightList.size(); i++) {
            logger.info("解析第(" + i + ")个");
            try {
                fi = roundTripFlightList.getJSONObject(i);
                //flightInfo［0］代表去程，［1］代表回程
                flightInfo = fi.getJSONArray("FlightInfo");
                gofi = flightInfo.getJSONObject(0);

                flightDetail = gofi.getJSONArray("FlightDetail");
                goTransits = new ArrayList<TransitEntity>();
                for (int j = 0; j < flightDetail.size(); j++) {//多个航班为中转
                    tfi = flightDetail.getJSONObject(j);
                    transitEntity = PlaneInfoEntityBuilder.buildTransitEntity(tfi.getString("FlightNo"),
                            null, tfi.getString("AirlineCode"), tfi.getString("AirlineName"),
                            tfi.getString("AirlineName"), tfi.getString("DPort"), tfi.getString("DCityName"),
                            tfi.getString("APort"), tfi.getString("ACityName"), tfi.getString("CraftType"), TransitEntity.class);
                    transitEntity.setStartTime(DateUtils.parseDate(tfi.getString("DepartTime"), new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd H:mm:ss"}));
                    transitEntity.setEndTime(DateUtils.parseDate(tfi.getString("ArrivalTime"), new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd H:mm:ss"}));
                    if (tfi.containsKey("TransferTime"))
                        transitEntity.setStayTime(XieChenFormatDataUtils.formatStayTime(tfi.getString("TransferTime")));
                    goTransits.add(transitEntity);
                }
                dpie = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, goTransits.get(0).getCarrierKey(),
                        goTransits.get(0).getCarrierName(), goTransits.get(0).getCarrierFullName(),
                        DateFormatUtils.format(goTransits.get(0).getStartTime(), "yyyy-MM-dd HH:mm:ss"),
                        DateFormatUtils.format(goTransits.get(goTransits.size() - 1).getEndTime(), "yyyy-MM-dd HH:mm:ss"),
                        goTransits.get(0).getFlightNo(), null, null, null, goTransits.get(0).getFlightType(), DoublePlaneInfoEntity.class);
                dpie.setStartTime(goTransits.get(0).getStartTime());
                dpie.setEndTime(goTransits.get(goTransits.size() - 1).getEndTime());
                dpie.getTransits().addAll(goTransits);
                //return trip
                backfi = flightInfo.getJSONObject(1);
                flightDetail = backfi.getJSONArray("FlightDetail");
                backTransits = new ArrayList<ReturnTransitEntity>();
                for (int j = 0; j < flightDetail.size(); j++) {//多个航班为中转
                    tfi = flightDetail.getJSONObject(j);
                    returnTransitEntity = PlaneInfoEntityBuilder.buildTransitEntity(tfi.getString("FlightNo"),
                            null, tfi.getString("AirlineCode"), tfi.getString("AirlineName"),
                            tfi.getString("AirlineName"), tfi.getString("DPort"), tfi.getString("DCityName"),
                            tfi.getString("APort"), tfi.getString("ACityName"), tfi.getString("CraftType"), ReturnTransitEntity.class);
                    returnTransitEntity.setStartTime(DateUtils.parseDate(tfi.getString("DepartTime"), new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd H:mm:ss"}));
                    returnTransitEntity.setEndTime(DateUtils.parseDate(tfi.getString("ArrivalTime"), new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd H:mm:ss"}));
                    if (tfi.containsKey("TransferTime"))
                        returnTransitEntity.setStayTime(XieChenFormatDataUtils.formatStayTime(tfi.getString("TransferTime")));
                    backTransits.add(returnTransitEntity);
                }
                rdpie = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, backTransits.get(0).getCarrierKey(),
                        backTransits.get(0).getCarrierName(), backTransits.get(0).getCarrierFullName(),
                        DateFormatUtils.format(backTransits.get(0).getStartTime(), "yyyy-MM-dd HH:mm:ss"),
                        DateFormatUtils.format(backTransits.get(backTransits.size() - 1).getEndTime(), "yyyy-MM-dd HH:mm:ss"),
                        backTransits.get(0).getFlightNo(), null, null, null, backTransits.get(0).getFlightType(), ReturnDoublePlaneInfoEntity.class);
                rdpie.setStartTime(backTransits.get(0).getStartTime());
                rdpie.setEndTime(backTransits.get(backTransits.size() - 1).getEndTime());
                rdpie.getReturnTransits().addAll(backTransits);

                dpie.getReturnPlaneInfos().add(rdpie);

                //价格,会有多个舱位的价格
                fareList = fi.getJSONArray("FareList");
                for (int k = 0; k < fareList.size(); k++) {
                    cabin = fareList.getJSONObject(k);
                    //只获得经济舱的数据，这里写死（否则取得的JSON模型与我们的模型对不上，取得的模型打包价下有时是有多个的不同舱位的）
                    goCabin = PlaneInfoEntityBuilder.buildCabinInfo("经济舱", null, null,
                            null, null, null, null, cabin.containsKey("TicketLack") ? cabin.getString("TicketLack") : null, CabinEntity.class);
                    backCabin = PlaneInfoEntityBuilder.buildCabinInfo("经济舱", null, null,
                            null, null, null, null, cabin.containsKey("TicketLack") ? cabin.getString("TicketLack") : null, ReturnCabinEntity.class);
                    dpie.getCabins().add(goCabin);
                    rdpie.getReturnCabins().add(backCabin);
                    CabinRelationEntity relation = new CabinRelationEntity();
                    relation.setCabinId(goCabin.getId());
                    relation.setReturnCabinId(backCabin.getId());
                    relation.setFullPrice(cabin.getDouble("Price"));
                    relation.setTaxesPrice(cabin.getDouble("Tax"));
                    relation.setTotalFullPrice(relation.getFullPrice() + relation.getTaxesPrice());
                    dpie.getCabinRelations().add(relation);
                }
                roundTrips.add(dpie);
            } finally {
                dpie = null;
                rdpie = null;
                goTransits = null;
                transitEntity = null;
                backTransits = null;
                returnTransitEntity = null;
                goCabin = null;
                backCabin = null;
                fi = null;
                gofi = null;
                backfi = null;
                tfi = null;
                cabin = null;
                flightInfo = null;
                fareList = null;
                flightDetail = null;
            }
        }
    }

    public List<Object> fetchData() throws Exception {
        List<Object> results = new ArrayList<Object>();
        String html = null;
        JSONObject firstJson = null;
        JSONObject j = null;
        try {
            logger.info("开始进入第一个页面。。。。");
            this.fetchEnterPage();
            logger.info("第一次（直飞）航班抓取。。。。");
            html = this.fetchFirstSearch();
            firstJson = JSONObject.fromObject(html);
            logger.info("解析直飞航班。。。。");
            this.parseJSONData(firstJson);
            logger.info("第二次（中转）航班抓取。。。。");
            html = this.fetchSecondSearch(firstJson);
            j = JSONObject.fromObject(html);
            logger.info("解析中转航班。。。。");
            this.parseJSONData(j);
            //暂时不取多段程的
            //logger.info("第三次（多程）航班抓取。。。。");
            //html = this.fetchThirdSearch(firstJson);
            //j = JSONObject.fromObject(html);
            //logger.info("解析多程航班。。。。");
            //this.parseJSONData(j);
            logger.info("获得的航班数量为：" + roundTrips.size());
            PlaneInfoEntityBuilder.buildLimitPrice(roundTrips);
            results.addAll(roundTrips);
        } finally {
            html = null;
            firstJson = null;
            j = null;
        }
        return results;
    }

    //机场和城市代码转换。
    private String convertCityCode(String airportCode) {
        String cityCode = airportCode.toUpperCase();
        if (airportCityMap.keySet().contains(cityCode)) {
            cityCode = airportCityMap.get(cityCode);
        }
        return cityCode.toLowerCase();
    }

    private static Map<String, String> airportCityMap = Maps.newHashMap();

    static {
        airportCityMap.put("PEK", "BJS");
        airportCityMap.put("PVG", "SHA");
        airportCityMap.put("EWR", "NYC");
        airportCityMap.put("LHR", "LON");
        airportCityMap.put("ORD", "CHI");
        airportCityMap.put("JFK", "NYC");
        airportCityMap.put("CDG", "PAR");
        airportCityMap.put("YYZ", "YTO");
        airportCityMap.put("LHR", "LON");
        airportCityMap.put("HKG", "LAX");
        airportCityMap.put("CDG", "PAR");
        airportCityMap.put("IAD", "WAS");
        airportCityMap.put("SVO", "MOW");
//        airportCityMap.put("LAX", "LAX");
//        airportCityMap.put("FRA", "FRA");
//        airportCityMap.put("SYD", "SYD");
//        airportCityMap.put("SFO", "SFO");
//        airportCityMap.put("HNL", "HNL");
//        airportCityMap.put("SEA", "SEA");
//        airportCityMap.put("YVR", "YVR");
//        airportCityMap.put("MUC", "MUC");
//        airportCityMap.put("BOS", "BOS");
//        airportCityMap.put("FRA", "FRA");


    }
}
